1. /* sdftrinf.cpp by K.Tsuru */
  2. // function ID 3201 DRADIX
  3. /*************************************************************************
  4. SDouble class
  5. It provides the method to evaluate sin(x), cos(x) or tan(x) functions.
  6. It returns "sign" which must be attached. When sign=0 "y" has an exact
  7. value (-1.0, 0, or 1.0). If you set *func=COS_CALC, SIN_CALC or TAN_CALC,
  8. the function to be used can be gotten by enum number
  9. {COS_CALC, SIN_CALC, TAN_CALC, COT_CALC}.
  10. Refering the value of "*func" the value of sin(y), cos(y), tan(y) or cot(y)
  11. is calculated and if the returned value "sign" is negative you have to change
  12. the sign.
  13. sign == 0 : sin(x) or cos(x) = y ----- y = 1.0 , 0 or -1.0, [+|-]sqrt(0.5)
  14. sign != 0 : sin(x) or cos(x) = sign*(*func)(y) (|y|<pi/4 )
  15. add "quadrant" of "x" Ver. 2.18
  16. ***************************************************************************/
  17. #ifndef SN_H
  18. #include "sn.h"
  19. #endif
  20. int GetTriCalcMethod(const SDouble& x, SDouble& y, int* func, int* quadrant) {
  21. const SDouble pi2 = MPi2(); // pi/2
  22. const SDouble pi4 = MPi4(); // pi/4
  23. const SDouble m2pi = M2Pi(); // 2/pi
  24. if(x.Sign(3201) == 0){
  25. if(quadrant != NULL) *quadrant = 0;
  26. y = (*func == COS_CALC) ? 1.0 : 0.0;
  27. return 0;
  28. }
  29. double dblX = doubleD(x, 0);
  30. if(fabs(dblX) < M_PI_4){ // |x| < pi/4
  31. if(quadrant != NULL) *quadrant = dblX > 0 ? 1 : 4;
  32. y = Dabs(x); return (*func == COS_CALC) ? 1.0 : x.Sign(); // cos(x) >0, sin(x) has the same sign as x
  33. }
  34. /*
  35. It reduces |x| < pi/4.
  36. When |x| has a large value it raises up the precision by the figures of exponent.
  37. It will be rare that |x|>=DRADIX, the recalculation of pi is necessary, then
  38. when PreferSpeed is ON it does not raise the precision.
  39. */
  40. #ifndef NDEBUG
  41. assert(x.NetRdxExp() >= 0);
  42. #endif
  43. int up = 2;
  44. uint upPrec = (uint)max(up, x.NetRdxExp()); // x.NetRdxExp() ~ 10 , |x| is very large
  45. if(SNManager::PreferSpeed() == ON) upPrec = 0;
  46. RealSize C;
  47. const SDouble HALF(0.5);
  48. SDouble n, Y;
  49. if(upPrec) C.SetEffFig(x.EffFig()+upPrec, C.TEMP_EXTEND); //temporally raise up the precision
  50. Y = Modf(x*m2pi, n);// |x|/(pi/2) = n+Y (n:integer, 0<=|Y|< 1.0) // very fast
  51. if(Y.IsPossibleToRound(2)) Y.Round();
  52. if(quadrant != NULL) { //Ver. 2.18 (May 9, 2007)
  53. SLong N;
  54. N = n;
  55. int r4 = N(0) % 4, qd = 0; // r4 = |n| % 4
  56. if( n.Sign() >= 0 && Y.Sign() > 0) qd = r4 + 1; // n%4 + 1
  57. else if( n.Sign() <= 0 && Y.Sign() < 0) qd = 4 - r4;// 4 - |n|%4
  58. *quadrant = qd; // <= 4
  59. }
  60. int c = DDCompare(Y, HALF); //It comapres the absolute values.
  61. if(c > 0){ // |Y| > 0.5, c> 0
  62. if(Y.Sign() > 0) n += ONE; // Y > 0.5, n+Y = (n+1) + (Y-1)
  63. else n -= ONE; // Y < -0.5, n+Y = (n-1) + (Y+1)
  64. } else if(c==0) {// Y=1/2 |x| = pi/4
  65. y = Sqrt(0.5);
  66. if((x.Sign() < 0) && (*func == SIN_CALC)) y.ChangeSign();
  67. return 0;
  68. }
  69. y = x - n*pi2; // y = x - n*pi/2;, |y| <= pi/4 y = pi/4 - pi/2 = -pi/4
  70. if(upPrec){ C.SetEffFig(0); y.Reform(3201); }
  71. #ifndef NDEBUG
  72. assert(n.RdxExp() >= 0);
  73. #endif
  74. //It determines the sign and function to be used. "n" is an integer.
  75. int sgn, uf = *func, nsgn = n.Sign(3201);
  76. uint n1pos = (uint)n.RdxExp();
  77. fType nL = n(n1pos), k; //the first position of n
  78. //The operator() returns zero for the argument without range.
  79. // x = n*pi/2 + y
  80. // sin(x) = cos(n*pi/2)*sin(y) + sin(n*pi/2)*cos(y)
  81. // cos(x) = cos(n*pi/2)*cos(y) - sin(n*pi/2)*sin(y)
  82. if(nL & 1){ // n = 2k+1, x = (2k+1)*pi/2 + y
  83. k = (nL -1)/2;
  84. if(uf == COS_CALC){
  85. // cos(x) = - sin(n*pi/2)*sin(y)
  86. *func = SIN_CALC; // cos(x) = (-1)^(k+1)sin(y)
  87. sgn = (k & 1) ? nsgn : -nsgn;
  88. } else if(uf == SIN_CALC){
  89. // sin(x) = sin(n*pi/2)*cos(y)
  90. *func = COS_CALC; // sin(x) = (-1)^k*cos(y)
  91. sgn = (k & 1) ? -nsgn : nsgn;
  92. } else { // tan(x) = -cot(y)
  93. *func = COT_CALC; sgn = -1;
  94. }
  95. } else { // n = 2k, x = k*pi + y
  96. k = nL/2;
  97. if(uf == COS_CALC){
  98. // cos(x) = cos(k*pi)*cos(y)
  99. sgn = (k & 1) ? -1 : 1; // cos(x) = (-1)^k*cos(y)
  100. } else if(uf == SIN_CALC){
  101. // sin(x) = cos(k*pi/2)*sin(y)
  102. sgn = (k & 1) ? -1 : 1; // sin(x) = (-1)^k*sin(y)
  103. } else sgn = 1; // tan(x) = tan(y)
  104. }
  105. /*
  106. When |x| is very large and very close to n*(pi/2), in the evaluation y=x-n*(pi/2)
  107. a cancelation will occure, then "y.IsMLT(one)" must not be used.
  108. */
  109. if(y.IsMLT(x)){ // y = 0, x = n*(pi/2), exact value. It does not use "y.IsMLT(one)".
  110. if(*func == COS_CALC) y = sgn;
  111. else if(*func == COT_CALC) y.SetError(y.DOMAIN_ERR,"Tan",3201); // 1/tan(n*pi) = 1/0
  112. else y.SetZero(); // y = 0 for sin(y)
  113. sgn = 0;
  114. }
  115. return sgn;
  116. }

sdftrinf.cpp : last modifiled at 2017/09/03 16:01:42(4,659 bytes)
created at 2017/10/07 10:22:50
The creation time of this html file is 2017/10/07 11:29:39 (Sat Oct 07 11:29:39 2017).